package nl.hanze.monoalphabetic.ui;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
import nl.hanze.monoalphabetic.controller.MainController;
import nl.hanze.monoalphabetic.domain.CharacterFrequency;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;

/**
 *
 * @author alex
 */
public class AnalyzePanel extends JPanel {

    MainController mainController;
    private JTextPane txtInput, txtOutput;
    private DefaultCategoryDataset dataset;
    private HashMap<Character, Character> deConversion;
    private List<CharacterFrequency> refList;
    private List<CharacterFrequency> compareList;
    private List<Character> alphabet;
    private List<JComboBox> comboBoxList;
    private List<JLabel> refOneletterLabList, comOneLetterLabelList, refTwoLetters, compareTwoLetters;
    private List<JLabel> refThreeLetterWord, comThreeLetterWord, refTwoLetterWord, comTwoLetterWord;
    private List<JLabel> refThreeLetters, comThreeLetters;
    private JLabel missingLetters;
    private final Font labelFont;
    private Highlighter.HighlightPainter yellow;
    private final Font textFont;

    public AnalyzePanel(MainController mainController) {
        this.mainController = mainController;
        deConversion = new HashMap<>(26);
        labelFont = new Font("Courier new", Font.BOLD, 13);
        textFont = new Font("Courier new", Font.PLAIN, 14);

        alphabet = new ArrayList<>();
        for (int i = 0; i < 26; i++) {
            alphabet.add((char) (i + 'a'));
        }

        comboBoxList = new ArrayList<>();
        refOneletterLabList = new ArrayList<>();
        comOneLetterLabelList = new ArrayList<>();

        refTwoLetters = new ArrayList<>();
        compareTwoLetters = new ArrayList<>();

        refThreeLetters = new ArrayList<>();
        comThreeLetters = new ArrayList<>();

        comTwoLetterWord = new ArrayList<>();
        refTwoLetterWord = new ArrayList<>();

        comThreeLetterWord = new ArrayList<>();
        refThreeLetterWord = new ArrayList<>();

        yellow = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW);

        setLayout(null);

        addInputPanel();
        addGraphPanel();
        addOutputPanel();
        addStatisticsPanel();
        setVisible(true);
    }

    /**
     * Voeg inputvelden toe. NB Buttons worden niet gebruikt vanwege de
     * keylistener op inputveld.
     */
    public void addInputPanel() {
        txtInput = new JTextPane();
        JScrollPane scrollPane = new JScrollPane(txtInput);
        scrollPane.setBounds(20, 10, 600, 160);
        add(scrollPane);

        txtInput.setFont(textFont);
        
        txtInput.addKeyListener(new KeyAdapter() {

            @Override
            public void keyReleased(KeyEvent e) {
                generateFrequencyTable();
                updateStatistics();
                generateDeConversion();
                deScrambleText();
                txtInput.getHighlighter().removeAllHighlights();
            }
        });


        JButton butAnalyze = new JButton("Analyseer text");
        butAnalyze.setBounds(20, 165, 150, 25);
        //add(butAnalyze);

        butAnalyze.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                //mainController.generateConversionTable();
                //txtOutput.setText(mainController.scrambleText(txtInput.getText()));
//                generateDeConversion();
//                deScrambleText();
            }
        });

        JButton butGenFreqTable = new JButton("Frequentie tabel");
        butGenFreqTable.setBounds(200, 165, 150, 25);
        //add(butGenFreqTable);

        butGenFreqTable.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
//                deScrambleText();
            }
        });


        JLabel butMapping = new JLabel("Mapping");
        butMapping.setBounds(640, 10, 120, 25);
        add(butMapping);

        missingLetters = new JLabel();
        missingLetters.setBounds(640, 610, 300, 25);
        add(missingLetters);

        //Genereer comboboxen
        for (int i = 0; i < 26; i++) {
            final JLabel label = new JLabel((char) (i + 'a') + "=>");
            label.setBounds(640, i * 22 + 40, 50, 20);
            add(label);

            final JComboBox combo = new JComboBox();
            combo.setBounds(670, i * 22 + 40, 50, 20);
            combo.setModel(new DefaultComboBoxModel(alphabet.toArray()));

            combo.setSelectedItem((char) (i + 'a'));
            comboBoxList.add(combo);
            add(combo);
        }

        //Add actionlisteners to combobox
        for (final JComboBox combo : comboBoxList) {

            combo.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    Character c = (Character) combo.getSelectedItem();
                    if (c != null) {
                        checkComboBox(c, combo);
                        generateDeConversion();
                        deScrambleText();
                        missingLetters();
                    }
                }
            });
        }
    }

    public void addOutputPanel() {
        txtOutput = new JTextPane();
        txtOutput.setEditable(false);
        JScrollPane scrollPane = new JScrollPane(txtOutput);
        txtOutput.setFont(textFont);
        
        txtOutput.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                try {
                    txtInput.getHighlighter().removeAllHighlights();
                    txtInput.getHighlighter().addHighlight(txtOutput.getCaretPosition(), txtOutput.getCaretPosition() + 1, yellow);
                } catch (BadLocationException ex) {
                    Logger.getLogger(AnalyzePanel.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        
        });
        
        
        scrollPane.setBounds(20, 200, 600, 160);
        add(scrollPane);
    }

    /**
     * Voeg grafiek paneel toe
     */
    private void addGraphPanel() {

        dataset = new DefaultCategoryDataset();

        JFreeChart chart = ChartFactory.createBarChart(
                "", // chart title
                "", // domain axis label
                "", // range axis label
                dataset, // data
                PlotOrientation.VERTICAL, // orientation
                true, // include legend
                true, // tooltips?
                false // URLs?
                );

        ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setBounds(20, 390, 600, 280);
        add(chartPanel);
    }

    /**
     * Maak statistiekvelden aan
     */
    public void addStatisticsPanel() {
        int vDistance = 22;

        JLabel labComp = new JLabel("D 1L");
        labComp.setBounds(730, 10, 40, 25);
        add(labComp);

        for (int i = 0; i < 26; i++) {
            JLabel label = new JLabel();
            label.setBounds(730, i * vDistance + 37, 60, 25);
            label.setFont(labelFont);
            add(label);
            comOneLetterLabelList.add(label);
        }

        JLabel labRef = new JLabel("R 1L");
        labRef.setBounds(800, 10, 50, 25);
        add(labRef);


        for (int i = 0; i < 26; i++) {
            JLabel label = new JLabel();
            label.setBounds(800, i * vDistance + 37, 60, 25);
            label.setFont(labelFont);
            add(label);
            refOneletterLabList.add(label);
        }

        JLabel labTwoRef = new JLabel("D 2L");
        labTwoRef.setBounds(870, 10, 100, 25);
        add(labTwoRef);

        for (int i = 0; i < 26; i++) {
            JLabel label = new JLabel();
            label.setBounds(870, i * vDistance + 37, 150, 25);
            label.setFont(labelFont);
            add(label);
            compareTwoLetters.add(label);
        }

        JLabel labTwoCom = new JLabel("R 2L");
        labTwoCom.setBounds(910, 10, 100, 25);
        add(labTwoCom);

        for (int i = 0; i < 26; i++) {
            JLabel label = new JLabel();
            label.setBounds(910, i * vDistance + 37, 150, 25);
            label.setFont(labelFont);
            add(label);
            refTwoLetters.add(label);
        }

        JLabel labTwoWordCom = new JLabel("D 2W");
        labTwoWordCom.setBounds(950, 10, 100, 25);
        add(labTwoWordCom);

        for (int i = 0; i < 26; i++) {
            JLabel label = new JLabel();
            label.setBounds(950, i * vDistance + 37, 150, 25);
            label.setFont(labelFont);
            add(label);
            comTwoLetterWord.add(label);
        }

        JLabel labTwoWordRef = new JLabel("R 2W");
        labTwoWordRef.setBounds(990, 10, 100, 25);
        add(labTwoWordRef);

        for (int i = 0; i < 26; i++) {
            JLabel label = new JLabel();
            label.setBounds(990, i * vDistance + 37, 150, 25);
            label.setFont(labelFont);
            add(label);
            refTwoLetterWord.add(label);
        }


        JLabel labThreeLetterCom = new JLabel("D 3L");
        labThreeLetterCom.setBounds(1040, 10, 100, 25);
        add(labThreeLetterCom);

        for (int i = 0; i < 26; i++) {
            JLabel label = new JLabel();
            label.setBounds(1040, i * vDistance + 37, 150, 25);
            label.setFont(labelFont);
            add(label);
            comThreeLetters.add(label);
        }

        JLabel labThreeLetterRef = new JLabel("R 3L");
        labThreeLetterRef.setBounds(1090, 10, 100, 25);
        add(labThreeLetterRef);

        for (int i = 0; i < 26; i++) {
            JLabel label = new JLabel();
            label.setBounds(1090, i * vDistance + 37, 150, 25);
            label.setFont(labelFont);
            add(label);
            refThreeLetters.add(label);
        }


        JLabel labThreeLetterWordCom = new JLabel("D 3W");
        labThreeLetterWordCom.setBounds(1140, 10, 100, 25);
        add(labThreeLetterWordCom);

        for (int i = 0; i < 26; i++) {
            JLabel label = new JLabel();
            label.setBounds(1140, i * vDistance + 37, 150, 25);
            label.setFont(labelFont);
            add(label);
            comThreeLetterWord.add(label);
        }

        JLabel labThreeLetterWordRef = new JLabel("R 3W");
        labThreeLetterWordRef.setBounds(1190, 10, 100, 25);
        add(labThreeLetterWordRef);

        for (int i = 0; i < 26; i++) {
            JLabel label = new JLabel();
            label.setBounds(1190, i * vDistance + 37, 150, 25);
            label.setFont(labelFont);
            add(label);
            refThreeLetterWord.add(label);
        }



        repaint();
    }

    /**
     * Genereer statistieken
     */
    public void generateFrequencyTable() {
        mainController.getCompareStatistics().generateStatistics(txtInput.getText());
        addData();
    }

    /**
     * Maak een deconversietabel aan
     */
    private void generateDeConversion() {
        deConversion.clear();
        for (int k = 0; k < 26; k++) {
            //Voeg teken toe voor null combobox
            Character c = comboBoxList.get(k).getSelectedItem() != null ? (Character) comboBoxList.get(k).getSelectedItem() : '#';
            deConversion.put((char) (k + 'a'), c);
        }
    }

    public void deScrambleText() {
        txtOutput.setText(mainController.deScrambleText(txtInput.getText(), deConversion));
        txtOutput.setCaretPosition(0);
    }

    /**
     * Checkt of letters meerdere keren voorkomen in de comboboxen, zet andere
     * combox op null.
     *
     * @param c
     * @param combobox
     */
    public void checkComboBox(Character c, JComboBox combobox) {
        //Character missing = missingLetter();

        for (JComboBox box : comboBoxList) {
            Character character = (Character) box.getSelectedItem();
            if (character == c && combobox != box) {
                box.setSelectedItem(null);
            }
        }
    }

    /**
     * Voeg data toe aan grafiek
     */
    public void addData() {
        dataset.clear();

        if (!mainController.getReferenceStatistics().getSingleCharacter().isEmpty()) {
            for (int i = 0; i < 26; i++) {
                dataset.addValue(mainController.getReferenceStatistics().getSingleCharacter().get(i).getFrequency(), "referentie", "" + (char) ('a' + i));
            }
        }

        for (int i = 0; i < 26; i++) {
            dataset.addValue(mainController.getCompareStatistics().getSingleCharacter().get(i).getFrequency(), "data", "" + (char) ('a' + i));
        }
    }

    /**
     * Update de statistieken
     */
    public void updateStatistics() {
        Comparator comp = Collections.reverseOrder();
        refList = new ArrayList<>(mainController.getReferenceStatistics().getSingleCharacter());
        Collections.sort(refList, comp);

        int i = 0;
        for (CharacterFrequency characterFrequency : refList) {
            refOneletterLabList.get(i).setText(characterFrequency.getCharacter() + "-"
                    + characterFrequency.getFormattedFrequency());
            i++;
        }

        List<CharacterFrequency> compList = new ArrayList<>(mainController.getCompareStatistics().getSingleCharacter());
        Collections.sort(compList, comp);
        i = 0;
        for (CharacterFrequency characterFrequency : compList) {
            comOneLetterLabelList.get(i).setText(characterFrequency.getCharacter() + "-"
                    + characterFrequency.getFormattedFrequency());
            i++;
        }

        i = 0;
        for (String s : mainController.getReferenceStatistics().getTopTwoLetterCombinations()) {
            refTwoLetters.get(i).setText(s);
            i++;
        }

        //Leeg labels
        for (JLabel lab : compareTwoLetters) {
            lab.setText("");
        }

        i = 0;
        for (String s : mainController.getCompareStatistics().getTopTwoLetterCombinations()) {
            compareTwoLetters.get(i).setText(s);
            i++;
        }

        //Leeg labels
        for (JLabel lab : comTwoLetterWord) {
            lab.setText("");
        }

        i = 0;
        for (String s : mainController.getCompareStatistics().getTopTwoLetterWords()) {
            comTwoLetterWord.get(i).setText(s);
            i++;
        }

        i = 0;
        for (String s : mainController.getReferenceStatistics().getTopTwoLetterWords()) {
            refTwoLetterWord.get(i).setText(s);
            i++;
        }

        //Leeg labels
        for (JLabel lab : comThreeLetters) {
            lab.setText("");
        }

        i = 0;
        for (String s : mainController.getCompareStatistics().getTopThreeLetterCombinations()) {
            comThreeLetters.get(i).setText(s);
            i++;
        }

        i = 0;
        for (String s : mainController.getReferenceStatistics().getTopThreeLetterCombinations()) {
            refThreeLetters.get(i).setText(s);
            i++;
        }

        //Leeg labels
        for (JLabel lab : comThreeLetterWord) {
            lab.setText("");
        }

        i = 0;
        for (String s : mainController.getCompareStatistics().getTopThreeLetterWords()) {
            comThreeLetterWord.get(i).setText(s);
            i++;
        }

        i = 0;
        for (String s : mainController.getReferenceStatistics().getTopThreeLetterWords()) {
            refThreeLetterWord.get(i).setText(s);
            i++;
        }




        repaint();
    }

    /**
     * Check welke letters nog niet in gebruik zijn
     */
    public void missingLetters() {
        List<Character> list = new ArrayList<>();
        List<Character> alpha = new ArrayList<>(alphabet);

        for (JComboBox box : comboBoxList) {
            Character character = (Character) box.getSelectedItem();
            list.add(character);
        }

        //Bereken verschil
        alpha.removeAll(list);

        //laat lijst met niet gebruikte letters zien.
        if (alpha.size() > 0) {
            StringBuilder b = new StringBuilder();
            //b.append("Niet gebruikt: ");
            for (Character character : alpha) {
                b.append(character);
                b.append(' ');
            }
            missingLetters.setText(b.toString());
        } else {
            missingLetters.setText("");
        }
    }

    /**
     * Check welke letter nog niet in gebruik is
     */
    public Character missingLetter() {
        List<Character> list = new ArrayList<>();
        List<Character> alpha = new ArrayList<>(alphabet);

        for (JComboBox box : comboBoxList) {
            Character character = (Character) box.getSelectedItem();
            list.add(character);
        }

        //Bereken verschil
        alpha.removeAll(list);
        Character c = alpha.size() > 0 ? alpha.get(0) : ' ';

        return c;
    }
}
